#include <iostream>
#include <cuda_runtime.h>
#include "../common/common.h"
#define DEVICENUM 0

__host__ void summaryCPU(float *array_a, float *array_b, float *array_res, int size)
{
    for (int i = 0; i < size; i++)
        array_res[i] = array_a[i] + array_b[i];
}

// 少了size参数？为什么呢？
__global__ void summaryGPU(float *array_a, float *array_b, float *array_res)
{
    // pass
}

int main(int argc, char **argv)
{
    cudaSetDevice(DEVICENUM);
    int nElem = 1 << 15;
    size_t nBytes = sizeof(float) * nElem;

    double time_cpu, time_gpu;

    // cpu申请内存并初始化数据
    float *host_array_a = (float *)malloc(nBytes);
    float *host_array_b = (float *)malloc(nBytes);
    float *host_array_res = (float *)malloc(nBytes);
    initialDataRandom(host_array_a, nElem);
    initialDataRandom(host_array_b, nElem);
    memset(host_array_res, 0, nBytes);
    // 计算cpu中两数组相加结果并计算时间
    time_cpu = get_time();
    summaryCPU(host_array_a, host_array_b, host_array_res, nElem);
    std::cout << "CPU Sum Array time:" << get_time() - time_cpu << "ms" << std::endl;

    // gpu内存申请
    float *device_array_a = nullptr;
    float *device_array_b = nullptr;
    float *device_array_res = nullptr;
    CHECK(cudaMalloc((float **)&device_array_a, nBytes));
    CHECK(cudaMalloc((float **)&device_array_b, nBytes));
    CHECK(cudaMalloc((float **)&device_array_res, nBytes));
    // 给gpu内存初始化数据
    CHECK(cudaMemcpy(device_array_a, host_array_a, nBytes, cudaMemcpyHostToDevice));
    CHECK(cudaMemcpy(device_array_b, host_array_b, nBytes, cudaMemcpyHostToDevice));
    CHECK(cudaMemset(device_array_res, 0, nBytes));
    // 调用kernel函数执行gpu数组加法运算
    summaryGPU<<<1, nElem>>>(device_array_a, device_array_b, device_array_res);
    CHECK(cudaDeviceSynchronize()); // 系统级同步，等待主机和设备完成所有工作
    // 将gpu运算结果复制到cpu后并与cpu结果进行比较
    float *res_gpu_to_cpu = (float *)malloc(nBytes);
    memset(res_gpu_to_cpu, 0, nBytes);
    CHECK(cudaMemcpy(res_gpu_to_cpu, device_array_res, nBytes, cudaMemcpyDeviceToHost));
    checkResult(host_array_res, res_gpu_to_cpu, nElem);

    // 释放gpu和cpu内存
    cudaFree(device_array_a);
    cudaFree(device_array_b);
    cudaFree(device_array_res);

    free(host_array_a);
    free(host_array_b);
    free(host_array_res);
    free(res_gpu_to_cpu);

    return 0;
}